package com.example.demo.util;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 极简订单ID生成工具类（支持主订单、子订单、售后单、退货单）
 * <p>
 * 编码规则：
 * - 主订单：M + yyyyMMddHHmmss + 6位序列 → M20251122123456000001
 * - 子订单：S + yyyyMMddHHmmss + 6位序列 → S20251122123456000001
 * - 售后单：A + yyyyMMddHHmmss + 6位序列 → A20251122123500000001 （After-sales）
 * - 退货单：R + yyyyMMddHHmmss + 6位序列 → R20251122123600000001 （Return）
 * <p>
 * 特性：线程安全、跨秒重置、类型隔离、零依赖、防错设计
 *
 * @author haochen78
 */
public class OrderIdGenerator {

    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    // M - 主订单
    private static final SequenceHolder MAIN_HOLDER = new SequenceHolder();
    // S - 子订单
    private static final SequenceHolder SUB_HOLDER = new SequenceHolder();
    // A - 售后单
    private static final SequenceHolder AFTER_SALES_HOLDER = new SequenceHolder();

    // 私有构造：禁止实例化
    private OrderIdGenerator() {
    }

    /**
     * 生成主订单号（M开头）
     */
    public static String generateMainOrderNo() {
        return generateWithHolder("M", MAIN_HOLDER);
    }

    /**
     * 生成子订单号（S开头）
     */
    public static String generateSubOrderNo() {
        return generateWithHolder("S", SUB_HOLDER);
    }

    /**
     * 生成售后单号（A开头，After-sales）
     */
    public static String generateAfterSalesNo() {
        return generateWithHolder("A", AFTER_SALES_HOLDER);
    }


    // 共享生成逻辑
    private static String generateWithHolder(String prefix, SequenceHolder holder) {
        String currentTimeStr = LocalDateTime.now().format(TIME_FORMATTER);

        synchronized (holder) {
            if (!currentTimeStr.equals(holder.lastTimeStr)) {
                holder.sequence.set(1);
                holder.lastTimeStr = currentTimeStr;
            }
            int seq = holder.sequence.getAndIncrement();
            if (seq > 999_999) {
                // 安全兜底：每秒最多999,999单，超限回绕（生产环境建议监控告警）
                holder.sequence.set(1);
                seq = 1;
            }
            return prefix + currentTimeStr + String.format("%06d", seq);
        }
    }

    // 序列持有者内部类
    private static class SequenceHolder {
        volatile String lastTimeStr = "";
        final AtomicInteger sequence = new AtomicInteger(1);
    }
}